#define MXMODULE_BITLINE
#define MXMODULE_BITDRAW
#define MXMODULE_FONTDRAW
#define MXMODULE_FONT8X14
#define MXMODULE_FONT8X16
#define MXMODULE_LOADFONT
#define MXMODULE_LOADTGA
#define MXMODULE_FONT_ALL
#define MXMODULE_DRIVER_ALL
#include "degfx/degfx.c"

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#define NUMBALLS 50

static char message[200];
static MX_BITMAP *ball, *ball2;

static void draw_intro(const MX_RECT * r)
{
	mx_rectfill(r->x1, r->y1, r->x2, r->y2, MXCOLOR_mediumslateblue);

	mx_blit(ball, 0, 0, 1, 1, mx_w(ball), mx_h(ball));

	mx_font_drawblock(0, message, -1, 1, 5 + mx_h(ball), MXCOLOR_white);
}

static MX_FONT *font = 0;
static MX_FONT *font2 = 0;
static MX_FONT *font3 = 0;

static void draw_font(const MX_RECT * r)
{
	mx_rectfill(r->x1, r->y1, r->x2, r->y2, MXCOLOR_mediumslateblue);

	mx_font_draw(font, "Loaded antialiased font", -1, 1, 1, MXCOLOR_white);

	mx_font_draw(font2, "Another loaded antialiased font", -1, 1, 30,
				 MXTRANS(MXCOLOR_white, 32));

	mx_font_draw(font3, "Loaded bitfont", -1, 1, 50, MXCOLOR_white);

	mx_font_draw(&mx_font_8x16, "Builtin 8x16 font", -1, 1, 80, MXCOLOR_white);

	mx_font_draw(&mx_font_8x14, "Builtin 8x14 font", -1, 1, 110,
				 MXTRANS(MXCOLOR_white, 222));

	mx_font_draw(&mx_font_8x8, "Builtin 8x8 font", -1, 1, 140, MXCOLOR_white);

	mx_font_draw(0, "Press key to continue", -1, 1, 170, MXCOLOR_white);
}

static void draw_trans(const MX_RECT * r)
{
	mx_rectfill(r->x1, r->y1, r->x2, r->y2, MXCOLOR_mediumslateblue);

	mx_font_draw(font, "Transparency support", -1, 1, 1, MXCOLOR_white);

	mx_blit(ball, 0, 0, 1, 30, MXDEFAULT, MXDEFAULT);
	mx_blit(ball2, 0, 0, 30, 60, MXDEFAULT, MXDEFAULT);

	mx_blittrans(ball, 0, 0, 60, 45, MXDEFAULT, MXDEFAULT, 205);

	mx_font_draw(0, "Press key to continue", -1, 1, 150, MXCOLOR_white);
}

static MX_RECT rect[NUMBALLS];
static int rate[NUMBALLS];
static int trans[NUMBALLS];
static int framecount, fps;

static void draw_scene(const MX_RECT * r)
{
	int i;

	/* Draw background */
	mx_rectfill(r->x1, r->y1, r->x2, r->y2, MXCOLOR_mediumslateblue);

	/* Draw sprites on background */
	for (i = 0; i < NUMBALLS; i++) {
		const int t1 = (trans[i] & 0xff);
		const int t = (trans[i] & 0x100) ? (0xff - t1) : (t1);

		mx_blittrans(ball, 0, 0, rect[i].x1, rect[i].y1, MXDEFAULT, MXDEFAULT,
					 t & 0xff);
	}

	mx_font_drawblock(font, message, -1, 1, 1, MXCOLOR_white);
}

typedef struct DRIVER {
	const MX_DRIVER *driver;
	const char *name;
} DRIVER;

int main(int argc, char *argv[])
{
	int i;
	MX_GFX_ARGS args;
	time_t lasttime = clock();
	unsigned updatemessage = true;
	MX_BITMAP_ITER start, end;
	int drivercount = 0;

	DRIVER driver[] = {
		{&mx_driver_fullscreen, "Fullscreen"},
		{&mx_driver_windowed, "Windowed"},
		{&mx_driver_vga, "Vga"},
		{&mx_driver_13h, "13H"},
		{0, 0}
	};

	(void) argc;
	(void) argv;

	/* Set some startup values */
	memset(&args, 0, sizeof(args));
/*    args.w = 1024; */
/*    args.h = 768;  */
	args.c = 16;
	args.driver = driver[drivercount].driver;
/*    args.buffer = mx_bitmap(1024,768); */
/*    args.buffer = mx_bitmap(640, 15);  */

	/* Start the graphic system */
	if (!mx_gfx_start(&args))
		return 1;

	/* Load the bitmap */
	ball = mx_bitmap_tga("title.tga");
	if (!ball) {
		mx_gfx_stop();
		perror("Could not load title.tga");
		exit(1);
	}

	/* Draw the intro screen */
	sprintf(message,
			"Welcome to the DEGFX library\n\n" "    Driver: %s\n"
			"    Screen: %i x %i x %i\n" "Buffersize: %i x %i\n"
			"\nPress key to continue", args.title, args.w, args.h, args.c,
			mx_w(args.buffer), mx_h(args.buffer));
	mx_gfx_redraw(draw_intro);

	while (mx_gfx_poll()) {
		mx_gfx_pointer(0, 0, 0);

		if (mx_gfx_key(0, 0))
			break;
	}

	/* Do the font screen */
	font = mx_font_pcx("./font/font.pcx", 32);
	font2 = mx_font_pcx("./font/font2.pcx", 32);
	font3 = mx_font_pcx("./font/arial.pcx", 32);

	mx_gfx_redraw(draw_font);

	while (mx_gfx_poll()) {
		mx_gfx_pointer(0, 0, 0);

		if (mx_gfx_key(0, 0))
			break;
	}

	/* Do the transparency screen */
	ball2 = mx_bitmap_clone(ball);

	start = mx_bitmap_begin(ball2);
	end = mx_bitmap_end(ball2);
	while (start != end) {
		*start = MXTRANS(*start, 64);
		++start;
	}

	mx_gfx_redraw(draw_trans);

	while (mx_gfx_poll()) {
		mx_gfx_pointer(0, 0, 0);

		if (mx_gfx_key(0, 0))
			break;
	}

	/* Setup the movement */
	for (i = 0; i < NUMBALLS; i++) {
		rect[i].x1 = rand() % (args.w - mx_w(ball));
		rect[i].y1 = rand() % (args.h - mx_h(ball));
		rect[i].x2 = rect[i].x1 + mx_w(ball);
		rect[i].y2 = rect[i].y1 + mx_h(ball);

		rate[i] = 0;
		while (rate[i] == 0)
			rate[i] = rand() % 20 - 10;

		trans[i] = rand() % (0xff);
	}

	strcpy(message, "");

	/* The main gfx loop */
	mx_gfx_redraw(draw_scene);

	while (mx_gfx_poll()) {
		MX_RECT both;
		time_t thistime;

		args = *mx_gfx_info();

		/* Move objects */
		for (i = 0; i < NUMBALLS; i++) {
			/* FIX ME: Separate declaration from initialisation to avoid C68
			   compiler problem */
			MX_RECT *ptr;
			MX_RECT old;

			ptr = &rect[i];
			old = *ptr;

			if (ptr->y1 >= args.screen.y2) {
				ptr->y1 = -mx_h(ball);
				ptr->y2 = 0;
			}

			if (ptr->y2 < 0) {
				ptr->y1 = args.screen.y2;
				ptr->y2 = args.screen.y2 + mx_h(ball);
			}

			ptr->y1 += rate[i];
			ptr->y2 += rate[i];

			trans[i] += 4;

			/* Mark objects as dirty */
			MXRECT_UNION(old, *ptr, both);
			mx_gfx_dirty(&both);
		}

		/* Next driver when a key is hit */
		if (mx_gfx_key(0, 0)) {
			++drivercount;

/* fputs(message, stderr);
            break; */

			if (driver[drivercount].driver) {
				args.driver = driver[drivercount].driver;

				if (!mx_gfx_start(&args))
					break;

			} else
				break;
		}

		/* Measure frames per second */
		++framecount;

		thistime = clock();
		if (thistime > (lasttime + CLOCKS_PER_SEC)) {
			fps = framecount;
			framecount = 0;
			lasttime = thistime;

			updatemessage = true;
		}

		if (updatemessage) {
			int w = mx_w(args.buffer);
			int h = mx_h(args.buffer);
			MX_RECT textrect;

			sprintf(message, "Buffer %i x %i (%i Kb)\n%s -> %s\nFPS: %i ", w, h,
					(w * h * 4) / 1024, driver[drivercount].name, args.title,
					fps);

			mx_font_blocksize(font, message, -1, &w, &h, 0);
			textrect.x1 = 1;
			textrect.y1 = 1;
			textrect.x2 = 1 + w;
			textrect.y2 = 1 + h;

			mx_gfx_dirty(&textrect);

			updatemessage = false;
		}

		mx_gfx_pointer(0, 0, 0);
	}

	if (font)
		mx_delete(font);
	if (font2)
		mx_delete(font2);
	if (font3)
		mx_delete(font3);
	if (ball2)
		mx_delete(ball2);
	if (ball)
		mx_delete(ball);
	mx_gfx_stop();

	return 0;
}
